home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#19 (Apr 87)
/
help demo.c
/
help.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-03-11
|
15KB
|
542 lines
/************************************************
* help.c - demo program shows a new way to
* present on-line help
*
* Bill Rausch, Jan 1987
* Uses LightSpeed C™ (Think Technologies, Inc.)
***********************************************/
#include <EventMgr.h>
#include <MenuMgr.h>
#include <WindowMgr.h>
#include <ToolboxUtil.h>
#include <DialogMgr.h>
#include <FontMgr.h>
#include <TextEdit.h>
#include <ListMgr.h>
#include <strings.h>
#include <pascal.h>
#define NULL 0L
#define ACTIVATE 0
#define INACTIVATE 255
#define FILEID 256
#define ABOUT 1
#define HELP 2
#define QUIT 3
#define HELP_DLG 256
#define HELP_OK 1
#define HELP_BOX 2
#define HELP_LIST 3
#define HELP_STR 256 /* STR# containing topics */
#define MAX_HELPS 100 /* application dependent */
struct {
Rect text_box; /* user item dimensions */
Rect topic_box; /* user item dimensions */
TEHandle text;
ListHandle topics;
Rect d_rect; /* TextEdit's dest rect */
Rect v_rect; /* TextEdit's view rect */
int offset; /* d_rect vertical shift */
int lines_vis; /* number of lines visible */
ControlHandle text_scroll;
int max_text; /* max value of scroller */
int help_id[MAX_HELPS]; /* topics’ HELP IDs */
int num_topics; /* how many topics? */
int last_one; /* last cell clicked in */
} h;
pascal Boolean help_filter();
Boolean show_help();
pascal void help_action();
/************************************************
* Trivial main(), just enough to use a single
* menu with only three items: About..., Help...,
* and Quit. No DAs, no windows, no command key
* equivalents or other key strokes. */
main()
{
EventRecord the_event;
WindowPtr which_window;
int menu_id, item_number;
long menu_code;
int window_code;
MenuHandle filemenu;
FlushEvents(everyEvent, 0);
InitGraf(&thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
filemenu = GetMenu(FILEID);
InsertMenu(filemenu, 0);
DrawMenuBar();
InitCursor();
for (;;) /* event loop */
{
if (GetNextEvent(everyEvent, &the_event))
{
if (the_event.what == mouseDown)
{
window_code = FindWindow(the_event.where,
&which_window);
if (window_code == inMenuBar)
{
menu_code = MenuSelect(the_event.where);
menu_id = HiWord(menu_code);
item_number = LoWord(menu_code);
if (menu_id == FILEID)
{
if (item_number == ABOUT)
do_about(
"Help demo - Bill Rausch - Jan. 1987",
"LightSpeed C™ by Think Technologies");
else if (item_number == HELP)
do_help(HELP_STR);
else if (item_number == QUIT)
ExitToShell();
else
SysBeep(1);
}
HiliteMenu(0);
DrawMenuBar();
}
else
SysBeep(1);
}
else
SysBeep(1);
}
}
}
/***********************************************/
/* creates alert-like box, waits for mouseDown */
do_about(text1, text2)
char *text1, *text2;
{
long dummy;
Rect box;
Rect line;
GrafPtr old_port;
WindowPtr window;
EventRecord an_event;
SetRect(&line, 6, 5, 345, 25);
SetRect(&box, 75, 125, 425, 180);
window = NewWindow(NULL, &box, "", TRUE,
dBoxProc, -1L, TRUE, NULL);
GetPort(&old_port);
SetPort(window);
TextFont(systemFont);
TextBox(text1, (long)strlen(text1), &line,
teJustCenter);
OffsetRect(&line, 0, 28);
TextBox(text2, (long)strlen(text2), &line,
teJustCenter);
do {
GetNextEvent(everyEvent, &an_event);
} while (an_event.what != mouseDown);
DisposeWindow(window);
SetPort(old_port);
}
/************************************************
* Help routine that makes use of the List
* Manager to present user with a list of topics
* and help text about each one. The topics are
* stored as a STR# resource and the help texts
* are stored as HELP resources. Each topic
* string contains the number of its associated
* HELP resource.
* Note: requires Geneva 10 font to be present */
do_help(str_id)
int str_id;
{
DialogPtr the_dialog;
Handle scr_handle; /* scratch variable */
int scratch; /* scratch variable */
Str255 scr_str; /* scratch variable */
Rect hdata_rect; /* for list manager setup */
Point cell_size; /* for list manager setup */
Handle topics; /* for list manager setup */
int *n_t_ptr;
GrafPtr old_port;
/* Read STR#, get number topics */
topics = GetResource('STR#', str_id);
h.num_topics = *(int *)(*topics);
/* Read dialog box resource */
the_dialog = GetNewDialog(HELP_DLG, NULL, -1L);
GetPort(&old_port); /* save where we were */
SetPort(the_dialog);
/* get user item for topic list */
GetDItem(the_dialog, HELP_LIST, &scratch,
&scr_handle, &h.topic_box);
InsetRect(&h.topic_box, 1, 1);
/* leave room for vertical scroll bar */
h.topic_box.right -= 15;
SetRect(&hdata_rect, 0, 0, 1, h.num_topics);
SetPt(&cell_size, h.topic_box.right -
h.topic_box.left, 16);
h.topics = LNew(&h.topic_box, &hdata_rect,
cell_size, 0, the_dialog,
FALSE, FALSE, FALSE, TRUE);
(*h.topics)->selFlags = lOnlyOne;
/* restore rect for framing */
InsetRect(&h.topic_box, -1, -1);
read_help(h.topics,h.num_topics,h.help_id,str_id);
if (!show_help(the_dialog, h.topics,
h.help_id))
do_about("show_help()",
"returned an error.");
SetPort(old_port); /* put us back */
}
/************************************************
* Read the topics from the STR# resource. Add
* them to the List as they are read. Also, save
* the IDs in an array for use later in finding
* the proper HELP resource to display for each
* topic. */
read_help(topics, num_topics, help_id,
str_id)
ListHandle topics;
int num_topics;
int help_id[];
int str_id;
{
int i;
Str255 a_topic;
Point the_cell;
char *id_number;
Str255 strvar;
for (i=0; i<num_topics; i++)
{
GetIndString(a_topic, str_id, i+1);
PtoCstr(a_topic);
id_number = strchr(a_topic, (char)'\\');
/* terminate topic and point to number */
*id_number++ = '\0';
help_id[i] = atoi(id_number);
SetPt(&the_cell, 0, i);
LSetCell(a_topic, strlen(a_topic), the_cell,
topics);
}
SetPt(&the_cell, 0, 0);
LSetSelect((Boolean)TRUE, the_cell, topics);
LDoDraw((Boolean)TRUE, topics);
}
/************************************************
* Set up the help text for the first topic in
* the list. Call ModalDialog (with a filterProc
* to do all the work). Loop until user clicks
* OK. */
Boolean show_help(the_dialog, topics, help_id)
DialogPtr the_dialog;
ListHandle topics;
int help_id[];
{
GrafPtr old_port;
int item_hit; /* returned by ModalDialog */
int scr_int; /* scratch variable */
Handle scr_handle; /* scratch variable */
Boolean done = FALSE;
int i, buf_size;
Rect scroll_rect;
Handle the_help;
/* get user item for help text */
GetDItem(the_dialog, HELP_BOX, &scr_int,
&scr_handle, &h.text_box);
/* leave room for scroll bar */
h.text_box.right -= 16;
scroll_rect.right = h.text_box.right + 15;
scroll_rect.left = h.text_box.right - 1;
scroll_rect.top = h.text_box.top;
scroll_rect.bottom = h.text_box.bottom;
h.text_scroll = NewControl(the_dialog,
&scroll_rect, "", TRUE,
0, 0, 0, 16, NULL);
HiliteControl(h.text_scroll, INACTIVATE);
/* Set up TextEdit record for the help text */
h.d_rect.top = h.text_box.top + 1;
h.d_rect.left = h.text_box.left + 1;
h.d_rect.right = h.text_box.right - 1;
h.d_rect.bottom = 20000; /* infinity */
h.v_rect = h.text_box;
InsetRect(&h.v_rect, 1, 1);
h.text = TENew(&h.d_rect, &h.v_rect);
(*h.text)->txFont = geneva;
(*h.text)->txSize = 10;
h.last_one = 0; /* 1st topic selected */
h.offset = 0; /* at top left corner now */
h.lines_vis = (h.v_rect.bottom - h.v_rect.top)
/ (*h.text)->lineHeight;
/* put 1st topic’s text into help box */
the_help = GetResource('HELP', help_id[0]);
buf_size = SizeResource(the_help);
TEDeactivate(h.text);
TESetSelect(32767L, 32767L, h.text);
HLock(the_help);
TEInsert(*the_help, (long)buf_size, h.text);
HUnlock(the_help);
/* vertical scroll bar necessary? */
if ((*h.text)->nLines > h.lines_vis)
{
HiliteControl(h.text_scroll, ACTIVATE);
h.max_text = (((*h.text)->nLines) -
h.lines_vis) * (*h.text)->lineHeight;
SetCtlMax(h.text_scroll, h.max_text);
}
ShowWindow(the_dialog);
do {
ModalDialog(help_filter, &item_hit);
if (item_hit == HELP_OK)
done = TRUE;
} while (!done);
TEDispose(h.text);
LDispose(h.topics);
DisposDialog(the_dialog);
return TRUE;
}
/************************************************
* This routine handles activating and updating
* of the scroller and the box area. We must
* handle mouse downs in the scroller and text
* box, passing back TRUE, and pass FALSE back
* for everything else so the Dialog Manager does
* his thing on the other items. */
pascal Boolean help_filter(dp, ep, ip)
WindowPtr dp;
EventRecord *ep;
int *ip;
{
int part;
ControlHandle ch;
char tempchar; /* check keydown for RETURN */
Point mouse_loc;
int start_value, end_value, dummy, delta;
long a_cell;
int cell_num;
Handle the_help;
int buf_size;
int scr_int; /* scratch variable */
Handle scr_handle; /* scratch variable */
Rect scr_rect; /* scratch variable */
switch(ep->what)
{
case updateEvt:
/* is the update event for this window? */
if (ep->message == (long)dp)
{
/* outline default button */
GetDItem(dp, HELP_OK, &scr_int,
&scr_handle, &scr_rect);
InsetRect(&scr_rect, -4, -4);
PenSize(3, 3);
FrameRoundRect(&scr_rect, 16, 16);
PenNormal();
/* draw boxes around topics, text */
FrameRect(&h.topic_box);
FrameRect(&h.text_box);
/* update contents of boxes */
EraseRect(&h.v_rect);
TEUpdate(&h.v_rect, h.text);
LUpdate(dp->visRgn, h.topics);
}
return FALSE;
case keyDown:
/* convert return key to OK button */
tempchar = BitAnd(ep->message,
charCodeMask);
if (tempchar == '\r')
{
*ip = HELP_OK;
return TRUE;
}
return FALSE;
case mouseDown:
/* get our own copy of coordinates */
mouse_loc = ep->where;
GlobalToLocal(&mouse_loc);
part = FindControl(mouse_loc, dp, &ch);
if (part > 0)
{
/* is click in a scroll bar? */
if (ch == h.text_scroll)
{
if (part == inThumb)
{
if(TrackControl(ch, mouse_loc, NULL))
{
/* reposition help text */
delta = h.offset -
GetCtlValue(h.text_scroll);
TEScroll(0, delta, h.text);
h.offset -= delta;
}
}
else
TrackControl(ch, mouse_loc,
help_action);
return TRUE;
}
else if (ch == (*h.topics)->vScroll)
{
LClick(mouse_loc, ep->modifiers,
h.topics);
return TRUE;
}
else
return FALSE;
}
else if (PtInRect(mouse_loc, *h.topics))
{
/* click was in topics list so find which
* topic was selected and display the
* proper HELP resource */
LClick(mouse_loc, ep->modifiers,
h.topics);
a_cell = 0;
if (LGetSelect(TRUE, &a_cell, h.topics))
cell_num = HiWord(a_cell);
if (cell_num >= 0 &&
cell_num != h.last_one)
{
/* get rid of the old text */
TEDeactivate(h.text);
TESetSelect(0L, 32767L, h.text);
TEDelete(h.text);
if (cell_num < h.num_topics)
{
the_help = GetResource('HELP',
h.help_id[cell_num]);
buf_size = SizeResource(the_help);
}
else /* no topic selected so no help */
buf_size = 0;
if (buf_size > 0)
{
HLock(the_help);
TEInsert(*the_help, (long)buf_size,
h.text);
HUnlock(the_help);
}
/* reset the scroll bar */
SetCtlValue(h.text_scroll, 0);
/* reposition the help text */
delta = h.offset -
GetCtlValue(h.text_scroll);
TEScroll(0, delta, h.text);
h.offset -= delta;
/* scroll bar necessary? */
if ((*h.text)->nLines > h.lines_vis)
{
HiliteControl(h.text_scroll,
ACTIVATE);
h.max_text = (((*h.text)->nLines) -
h.lines_vis) *
(*h.text)->lineHeight;
SetCtlMax(h.text_scroll, h.max_text);
}
else
HiliteControl(h.text_scroll,
INACTIVATE);
/* finally, save the new topic */
h.last_one = cell_num;
}
return TRUE;
}
return FALSE;
default:
return FALSE;
}
}
/************************************************
* This routine is called by the Toolbox while
* executing the TrackControl() routine. It has
* to take care of scrolling the text when the
* up/down arrow and page parts of the scrollbar
* are clicked in. */
pascal void help_action(the_scroll, partcode)
ControlHandle the_scroll;
int partcode;
{
int value, delta;
switch (partcode)
{
case inUpButton:
value = GetCtlValue(the_scroll);
value = (value-(*h.text)->lineHeight > 0)
? value-(*h.text)->lineHeight
: 0;
SetCtlValue(the_scroll, value);
break;
case inPageUp: /* move 6 lines at a time */
value = GetCtlValue(the_scroll);
value = (value-6*(*h.text)->lineHeight > 0)
? value-6*(*h.text)->lineHeight
: 0;
SetCtlValue(the_scroll, value);
break;
case inDownButton:
value = GetCtlValue(the_scroll);
value = (value + (*h.text)->lineHeight <
h.max_text)
? value + (*h.text)->lineHeight
: h.max_text;
SetCtlValue(the_scroll, value);
break;
case inPageDown:/* move 6 lines at a time */
value = GetCtlValue(the_scroll);
value = (value + 6*(*h.text)->lineHeight <
h.max_text)
? value + 6*(*h.text)->lineHeight
: h.max_text;
SetCtlValue(the_scroll, value);
break;
}
delta = h.offset - GetCtlValue(h.text_scroll);
TEScroll(0, delta, h.text);
h.offset -= delta;
}